package calculator;

import control.Control;
import control.ControlSelector;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class Calculator {

    private ArrayDeque<String> inputDeque = new ArrayDeque();
    private Stack<String> deleteStack = new Stack();
    public void process(String input) {
        String last = inputDeque.peekLast();
        Control control = null;
        if (!isNumber(input)) {
            if (!"UNDO".equalsIgnoreCase(input) && !"REDO".equalsIgnoreCase(input)
                    && !"(".equals(input) &&!isNumber(last) && !")".equals(last)) {
                System.out.println("输入格式有误，已忽略当次输入");
                return;
            }
            control = ControlSelector.select(input, this);
            if (control != null) {
                control.control();
            }
        } else {
            if (!deleteStack.isEmpty()) {
                deleteStack.clear();
            }
        }
        if (control == null) {
            inputDeque.add(input);
        }
        System.out.println("current:" + inputDeque.toString());
    }

    private static boolean isOperatorOrNumber(String input) {
        return isNumber(input) || "+".equals(input) || "-".equals(input)
                || "*".equals(input) || "/".equals(input);
    }

    public double calculateTotal(List<String> array) {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < array.size();) {
            String element = array.get(i);
             if (!isNumber(element)) {
                 // 计算括号内容
                 String operatorStr = array.get(i);
                 if ("(".equals(operatorStr)) {
                     int endIndex = array.lastIndexOf(")");
                     if (endIndex == -1) {
                         System.err.println("括号不匹配，已忽略计算结果");
                         return 0;
                     }

                     List<String> sub = array.subList(i + 1, endIndex);
                     double subSum = calculateTotal(sub);
                     list.add(String.valueOf(subSum));
                     i = endIndex + 1;
                     continue;
                 }
             }
            list.add(element);
            i++;
        }

        return sum(list);
    }

    private double sum(List<String> array) {
        // 先计算*/符号，再计算+-
        Stack<String> stack = new Stack<>();
        for (int i = 0; i < array.size();i++) {
            String element = array.get(i);
            if (!isNumber(element)) {
                if ("*".equals(element)) {
                    double rtn = multiply(Double.parseDouble(stack.pop()), Double.parseDouble(array.get(++i)));
                    stack.push(String.valueOf(rtn));
                } else if ("/".equals(element)) {
                    double rtn = divide(Double.parseDouble(stack.pop()), Double.parseDouble(array.get(++i)));
                    stack.push(String.valueOf(rtn));
                } else {
                    stack.push(element);
                }
            } else {
                stack.push(element);
            }
        }

        ArrayList<String> list = new ArrayList<>(stack);
        double result = Double.parseDouble(list.get(0));
        for (int i = 0; i < list.size(); i++) {
            String element = list.get(i);
            if (!isNumber(element)) {
                if ("+".equals(element)) {
                    result = add(result, Double.parseDouble(list.get(++i)));
                } else if ("-".equals(element)) {
                    result = subtract(result, Double.parseDouble(list.get(++i)));
                }
            }
        }
        return result;
    }

    public static double multiply(double a, double b) {
        return a * b;
    }

    public static double divide(double a, double b) {
        return a / b;
    }

    public static double add(double a, double b) {
        return a + b;
    }

    public static double subtract(double a, double b) {
        return a - b;
    }

    public static boolean isNumber(String s) {
        if (s == null || s.length() == 0) {
            return false;
        }
        try {
            Double.parseDouble(s);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public ArrayDeque<String> getInputDeque() {
        return inputDeque;
    }

    public Stack<String> getDeleteStack() {
        return deleteStack;
    }

}